#include "ap_http_server.h"

#include "cJSON.h"

#define EXAMPLE_HTTP_QUERY_KEY_MAX_LEN  (64)
#define SCRATCH_BUFSIZE (10240)

static const char *AP_HTTP_SERVER = "AP_HTTP_SERVER";

// HTTP请求
// GET /index.html HTTP/1.1
// Host: www.example.com
// User-Agent: Mozilla/5.0
// Accept: text/html

// HTTP响应
// HTTP/1.1 200 OK
// Content-Type: text/html
// Content-Length: 137

// <html>
// <head>
//     <title>Example</title>
// </head>
// <body>
//     <h1>Hello, World!</h1>
// </body>
// </html>

static esp_err_t index_get_handler(httpd_req_t *req)
{
    char*  buf;
    size_t buf_len;
    char *file_content = NULL;
    esp_err_t ret = ESP_FAIL;
    size_t file_len = 0;

    // 获取Host
    buf_len = httpd_req_get_hdr_value_len(req, "Host") + 1;
    if (buf_len > 1) {
        buf = malloc(buf_len);
        if (httpd_req_get_hdr_value_str(req, "Host", buf, buf_len) == ESP_OK) {
            ESP_LOGI(AP_HTTP_SERVER, "Found header => Host: %s", buf);
        }
        free(buf);
    }

    ret = read_spiffs_file("/index.html", &file_content, &file_len);
    if (ret != ESP_OK) {
        httpd_resp_send_404(req);
        return ESP_FAIL;
    }

    httpd_resp_set_type(req, "text/html");

    // 返回响应
    httpd_resp_send(req, file_content, file_len);
    if (file_content) {
        free(file_content);
    }

    return ESP_OK;
}

static esp_err_t wifi_list_get_handler(httpd_req_t *req)
{
    // esp_err_t ret = ESP_FAIL;

    // 获取WiFi扫描的结果
    uint16_t number = 12;
    wifi_ap_record_t ap_info[12];
    uint16_t ap_count = 0;
    memset(ap_info, 0, sizeof(ap_info));

    get_wifi_ap_array(&number, ap_info, &ap_count);
    // char wifi_buf[12][33];

    // 动态分配字符指针数组
    char **fruits = (char **)malloc(number * sizeof(char *));
    if (fruits == NULL) {
        printf("Memory allocation failed\n");
        return 1;
    }

    // 动态分配并初始化每个字符串
    for (int i = 0; i < 12; i++) {
        fruits[i] = strdup((char *)ap_info[i].ssid);
    }

    // 打印字符串数组中的每个字符串
    // for (int i = 0; i < number; i++) {
    //     ESP_LOGI(AP_HTTP_SERVER, "Fruit %d: %s", i + 1, fruits[i]);
    // }
    
    // 示例数组
    // int array[] = {1, 2, 3, 4, 5};
    // int array_size = sizeof(array) / sizeof(array[0]);

    // 创建 JSON 对象
    cJSON *json_root = cJSON_CreateObject();
    // cJSON *json_array = cJSON_CreateIntArray(array, array_size);
    cJSON *json_array = cJSON_CreateStringArray((const char *const *)fruits, number);
    cJSON_AddItemToObject(json_root, "numbers", json_array);

    // 将 JSON 对象转换为字符串
    const char *json_response = cJSON_Print(json_root);

    // 设置内容类型为 JSON
    httpd_resp_set_type(req, "application/json");

    // 发送响应
    httpd_resp_send(req, json_response, strlen(json_response));

    // 释放分配的内存
    for (int i = 0; i < number; i++) {
        free(fruits[i]);
    }
    free(fruits);

    // 释放 JSON 对象
    cJSON_Delete(json_root);
    free((void *)json_response);

    return ESP_OK;
}

static esp_err_t ssid_passwd_set_handler(httpd_req_t *req)
{
    // 获取HTTP字段的长度
    // int total_len = req->content_len;
    char* buf = calloc(1, req->content_len + 1);
    int ret = ESP_FAIL;
    size_t off = 0;
    bool restart_val = false;

    ESP_LOGI(AP_HTTP_SERVER, "req->content_len length %d", req->content_len);

    if (!buf) {
        ESP_LOGE(AP_HTTP_SERVER, "Failed to allocate memory of %d bytes!", req->content_len + 1);
        httpd_resp_send_500(req);
        return ESP_FAIL;
    }

    while (off < req->content_len) {
        /* Read data received in the request */
        ret = httpd_req_recv(req, buf + off, req->content_len - off);
        if (ret <= 0) {
            if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
                httpd_resp_send_408(req);
            }
            free (buf);
            return ESP_FAIL;
        }
        off += ret;
        ESP_LOGI(AP_HTTP_SERVER, "recv length %d", ret);
    }

    buf[off] = '\0';

    ESP_LOGI(AP_HTTP_SERVER, "Received data: %s", buf);

    // 解析JSON数据
    cJSON *root = cJSON_Parse(buf);
    if (root == NULL) {
        ESP_LOGE(AP_HTTP_SERVER, "Failed to parse JSON");
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
        free(buf);
        return ESP_FAIL;
    }

    cJSON *ssid_json = cJSON_GetObjectItem(root, "ssid");
    cJSON *password_json = cJSON_GetObjectItem(root, "passwd");
    cJSON *restart_flag = cJSON_GetObjectItemCaseSensitive(root, "isRestart");

    if (!cJSON_IsString(ssid_json) || !cJSON_IsString(password_json) || !cJSON_IsBool(restart_flag)) {
        ESP_LOGE(AP_HTTP_SERVER, "Invalid JSON format");
        cJSON_Delete(root);
        free(buf);
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON format");
        return ESP_FAIL;
    }


    const char *ssid = ssid_json->valuestring;
    const char *password = password_json->valuestring;
    restart_val = cJSON_IsTrue(restart_flag);

    ESP_LOGI(AP_HTTP_SERVER, "Parsed SSID: %s", ssid);
    ESP_LOGI(AP_HTTP_SERVER, "Parsed Password: %s", password);

    ESP_LOGI(AP_HTTP_SERVER, "+++++> recv WiFi setting <+++++");

    // 把WIFI的SSID和密码保存到SPIFFS
    set_sta_ssid_passwid(ssid_json->valuestring, password_json->valuestring);

    cJSON_Delete(root);
    free(buf);

    // 获取config.json中的值
    uint8_t val_ssid[33] = {0};
    uint8_t val_password[65] = {0};
    get_sta_ssid_passwid(val_ssid, val_password);
    
    ESP_LOGI(AP_HTTP_SERVER, "val_ssid %s val_password %s", val_ssid, val_password);

    const char resp[] = "WiFi configuration received";
    httpd_resp_send(req, resp, HTTPD_RESP_USE_STRLEN);

    if (get_config_module() == AP_DNS) {
        // 重启ESP32,进入STA和AP模式
        set_config_module(AP_STA);
        esp_restart();
    }

    if (restart_val) {
        ESP_LOGI(AP_HTTP_SERVER, "Restart flag is true");
        // 重启ESP32
        esp_restart();
    }

    return ESP_OK;
}

static esp_err_t reset_dev_config(httpd_req_t *req)
{
    // 获取HTTP字段的长度
    // int total_len = req->content_len;
    char* buf = calloc(1, req->content_len + 1);
    int ret = ESP_FAIL;
    size_t off = 0;

    ESP_LOGI(AP_HTTP_SERVER, "req->content_len length %d", req->content_len);

    if (!buf) {
        ESP_LOGE(AP_HTTP_SERVER, "Failed to allocate memory of %d bytes!", req->content_len + 1);
        httpd_resp_send_500(req);
        return ESP_FAIL;
    }

    while (off < req->content_len) {
        /* Read data received in the request */
        ret = httpd_req_recv(req, buf + off, req->content_len - off);
        if (ret <= 0) {
            if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
                httpd_resp_send_408(req);
            }
            free (buf);
            return ESP_FAIL;
        }
        off += ret;
        ESP_LOGI(AP_HTTP_SERVER, "recv length %d", ret);
    }
    buf[off] = '\0';

    ESP_LOGI(AP_HTTP_SERVER, "Received data: %s", buf);

    // 解析JSON数据
    cJSON *root = cJSON_Parse(buf);
    if (root == NULL) {
        ESP_LOGE(AP_HTTP_SERVER, "Failed to parse JSON");
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
        free(buf);
        return ESP_FAIL;
    }

    cJSON *flag_json = cJSON_GetObjectItem(root, "flag");

    if (!cJSON_IsBool(flag_json)) {
        ESP_LOGE(AP_HTTP_SERVER, "Invalid JSON format");
        free(buf);
        cJSON_Delete(root);
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON format");
        return ESP_FAIL;
    }

    cJSON_Delete(root);
    free(buf);

    const char resp[] = "Device configuration reset";
    httpd_resp_send(req, resp, HTTPD_RESP_USE_STRLEN);

    // 重启ESP32,设置成AP_DNS模式
    set_config_module(AP_DNS);
    esp_restart();

    return ESP_OK;
}

static esp_err_t favicon_ico_get_handler(httpd_req_t *req)
{
    char *file_content = NULL;
    esp_err_t ret = ESP_FAIL;
    size_t file_len = 0;

    ret = read_spiffs_file("/favicon.ico", &file_content, &file_len);
    if (ret != ESP_OK) {
        httpd_resp_send_404(req);
        return ESP_FAIL;
    }

    httpd_resp_set_type(req, "image/x-icon");

    // 返回响应
    httpd_resp_send(req, file_content, file_len);
    if (file_content) {
        free(file_content);
    }

    return ESP_OK;
}

// HTTP错误（404）处理程序 - 将所有请求重定向到根页面。
esp_err_t http_404_error_handler(httpd_req_t *req, httpd_err_code_t err)
{
    // Set status
    httpd_resp_set_status(req, "302 Temporary Redirect");
    // Redirect to the "/" root directory
    httpd_resp_set_hdr(req, "Location", "/");
    // iOS requires content in the response to detect a captive portal, simply redirecting is not sufficient.
    httpd_resp_send(req, "Redirect to the captive portal", HTTPD_RESP_USE_STRLEN);

    ESP_LOGI(AP_HTTP_SERVER, "Redirecting to root");
    return ESP_OK;
}

const httpd_uri_t root_index = {
    .uri       = "/",
    .method    = HTTP_GET,
    .handler   = index_get_handler,
    .user_ctx  = NULL // 在用户上下文中传递响应字符串
};

const httpd_uri_t wifi_list = {
    .uri       = "/wifiList",
    .method    = HTTP_GET,
    .handler   = wifi_list_get_handler,
    .user_ctx  = NULL // 在用户上下文中传递响应字符串
};

const httpd_uri_t set_wifi = {
    .uri       = "/setWifi",
    .method    = HTTP_POST,
    .handler   = ssid_passwd_set_handler,
    .user_ctx  = NULL // 在用户上下文中传递响应字符串
};

const httpd_uri_t reset_dev = {
    .uri       = "/resetDev",
    .method    = HTTP_POST,
    .handler   = reset_dev_config,
    .user_ctx  = NULL // 在用户上下文中传递响应字符串
};

const httpd_uri_t favicon_ico = {
    .uri       = "/favicon.ico",
    .method    = HTTP_GET,
    .handler   = favicon_ico_get_handler,
    .user_ctx  = NULL // 在用户上下文中传递响应字符串
};


httpd_handle_t start_webserver(void)
{
    httpd_handle_t server = NULL;
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();

    // CONFIG_HTTPD_MAX_REQ_HDR_LEN 1024 // 增加URI长度限制
    // CONFIG_HTTPD_MAX_URI_LEN 1024     // 增加请求头的长度限制
    config.max_resp_headers = 20;        // 增加响应头的数量限制
    config.max_open_sockets = 13;
    
    config.lru_purge_enable = true;

    // Start the httpd server
    ESP_LOGI(AP_HTTP_SERVER, "Starting server on port: '%d'", config.server_port);
    if (httpd_start(&server, &config) == ESP_OK) {
        // Set URI handlers
        ESP_LOGI(AP_HTTP_SERVER, "Registering URI handlers");
        httpd_register_uri_handler(server, &root_index);
        httpd_register_uri_handler(server, &wifi_list);
        httpd_register_uri_handler(server, &favicon_ico);
        httpd_register_uri_handler(server, &set_wifi);
        httpd_register_uri_handler(server, &reset_dev);
        httpd_register_err_handler(server, HTTPD_404_NOT_FOUND, http_404_error_handler);
        return server;
    }

    ESP_LOGI(AP_HTTP_SERVER, "Error starting server!");
    return NULL;
}

void ap_http_demo()
{
    httpd_handle_t server = NULL;
    server = start_webserver();
}
